package com.petshop.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * 本类用于redis实现全局id
 */
@Component
public class RedisIdWorker {
    //定义一个初始时间，假设是2025.1.1.00:00时刻的秒数
    private static final long BEGIN_TIMESTAMP = 1735689600L;
    //定义序列号count的位数是32
    private static final int COUNT_BITS = 32;
    private StringRedisTemplate stringRedisTemplate;

    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public static void main(String[] args) {
        //设定一个时间的初始值
        LocalDateTime time = LocalDateTime.of(2025, 1, 1, 0, 0, 0);
        //将该值转换成秒数
        long second = time.toEpochSecond(ZoneOffset.UTC);
        //打印输出
        System.out.println(second);
    }

    //接受一个不同的业务前缀，以代表不同的业务需求，例如order业务、其他业务
    public long nextId(String servicePrefix) {
        //1 生成31位的时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSeconds = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSeconds - BEGIN_TIMESTAMP;

        //2 生成32位的序列号
        //2.1 获取当前日期，精确到天
        String date = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        /*
        此处如果无限次使用"icr"+servicePrefix+":"这个当作key，会导致该业务的所有数据存在同一个key里，
        那么自增的value终会有用完的一天，为此会在业务前缀的后边再加上一个时间戳例如：20250329表示当天的业务量，
        这样就避免了用尽的情况，还可以统计当天的下单情况。

        如果希望统计月订单业务情况，只需要修改时间的格式为yyyy:MM:dd，
        正好和redis的key值书写方式相匹配。只需要找到yyyy:MM前缀的值进行累加就可以了。
        */

//        increment()
//        这个方法用于对 Redis 中某个键对应的值进行自增操作。
//        如果键不存在，Redis 会自动创建这个键，并将其初始值设置为 然后进行自增操作。
//        如果键已经存在，Redis 会将其对应的值加
        //也就是说新的一天开始了，不填写value也不会出现空指针异常
        //2.2 实现自增长
        long count = stringRedisTemplate.opsForValue().increment("icr" + servicePrefix + date + ":");
        //3 拼接并返回
        //时间戳左移32位，空余除32个空位，值是0；让count和0做位或运算即可得到count本身了。
        return timestamp << COUNT_BITS | count;
    }
}
